home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 401-425 / disk_403 / rexxhostlib / rexxhostlib.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  15KB  |  729 lines

  1. /* $Revision Header * Header built automatically - do not edit! *************
  2.  *
  3.  *    (C) Copyright 1990 by MXM
  4.  *
  5.  *    Name .....: RexxHostLib.c
  6.  *    Created ..: Sunday 07-Jan-90 18:55
  7.  *    Revision .: 14
  8.  *
  9.  *    Date            Author          Comment
  10.  *    =========       ========        ====================
  11.  *    09-Sep-90       Olsen           Bug fixed in GetToken, added
  12.  *                                    IsSpace() and GetRexxClip()
  13.  *    24-May-90       Olsen           General rewrite, added new functions
  14.  *    26-Apr-90       Olsen           Supports short integers (16 bits)
  15.  *    13-Apr-90       Olsen           Added assembly language routines
  16.  *    31-Mar-90       Olsen           Rewrote RexxStrCmp
  17.  *    19-Mar-90       Olsen           More sanity checks
  18.  *    17-Mar-90       Olsen           Added RexxStrCmp, rewrote
  19.  *                                    CreateRexxHost/DeleteRexxHost,
  20.  *                                    ANSIfication
  21.  *    16-Mar-90       Olsen           Rework for Aztec 5.0 release
  22.  *    07-Jan-90       Olsen           Added string conversion functions
  23.  *    07-Jan-90       Olsen           Added GetToken
  24.  *    07-Jan-90       Olsen           - Empty log message -
  25.  *    07-Jan-90       Olsen           Removed bug in SendRexxCommand
  26.  *    07-Jan-90       Olsen           - Empty log message -
  27.  *    07-Jan-90       Olsen           Created this file!
  28.  *
  29.  ****************************************************************************
  30.  *
  31.  *    This Amiga shared library is based on example source code
  32.  *    written by Gary Samad & Bill Hawes.
  33.  *
  34.  * $Revision Header ********************************************************/
  35.  #define REVISION 14
  36.  
  37.     /* Main rexx library base. */
  38.  
  39. extern struct RxsLib *RexxSysBase;
  40.  
  41.     /* Global revision identifier. */
  42.  
  43. LONG Revision = REVISION;
  44.  
  45.     /* CreateRexxHost(HostName):
  46.      *
  47.      *    Creates a RexxHost (special MsgPort) with a given name.
  48.      *    Returns NULL if port already exists.
  49.      */
  50.  
  51. struct RexxHost *
  52. CreateRexxHost(STRPTR HostName)
  53. {
  54.     struct RexxHostBase    *RexxHostBase;
  55.     struct RexxHost        *RexxHost;
  56.  
  57.         /* Valid name given? */
  58.  
  59.     if(HostName && HostName[0])
  60.     {
  61.             /* Already present? */
  62.  
  63.         if(!FindPort((char *)HostName))
  64.         {
  65.                 /* Allocate the port body. */
  66.  
  67.             if(RexxHost = (struct RexxHost *)AllocMem(sizeof(struct RexxHost),MEMF_PUBLIC | MEMF_CLEAR))
  68.             {
  69.                     /* Allocate a signal bit. */
  70.  
  71.                 if((RexxHost -> rh_Port . mp_SigBit = AllocSignal(-1)) != -1)
  72.                 {
  73.                         /* Initialize the MsgPort node head. */
  74.  
  75.                     RexxHost -> rh_Port . mp_Node . ln_Type    = NT_MSGPORT;
  76.                     RexxHost -> rh_Port . mp_Node . ln_Pri    = 1;
  77.  
  78.                         /* Allocate memory for MsgPort name. */
  79.  
  80.                     if(RexxHost -> rh_Port . mp_Node . ln_Name = (char *)AllocMem(StrLen((char *)HostName) + 1,MEMF_PUBLIC))
  81.                     {
  82.                             /* Copy the name. */
  83.  
  84.                         StrCpy(RexxHost -> rh_Port . mp_Node . ln_Name,(char *)HostName);
  85.  
  86.                             /* Deal with the rest of the flags. */
  87.  
  88.                         RexxHost -> rh_Port . mp_Flags        = PA_SIGNAL;
  89.                         RexxHost -> rh_Port . mp_SigTask    = SysBase -> ThisTask;
  90.  
  91.                             /* A dummy ID. */
  92.  
  93.                         RexxHost -> rh_SpecialID = 'REXX';
  94.  
  95.                             /* Finally add it to the public port list. */
  96.  
  97.                         AddPort(&RexxHost -> rh_Port);
  98.  
  99.                             /* And return it to the caller. */
  100.  
  101.                         return(RexxHost);
  102.                     }
  103.  
  104.                     FreeSignal(RexxHost -> rh_Port . mp_SigBit);
  105.                 }
  106.  
  107.                 FreeMem(RexxHost,sizeof(struct RexxHost));
  108.             }
  109.         }
  110.     }
  111.  
  112.     return(NULL);
  113. }
  114.  
  115.     /* DeleteRexxHost(RexxHost):
  116.      *
  117.      *    Deletes a MsgPort as created by CreateRexxHost().
  118.      *    Returns NULL, so user can do 'Host = DeleteRexxHost(Host);'.
  119.      */
  120.  
  121. VOID *
  122. DeleteRexxHost(struct RexxHost *RexxHost)
  123. {
  124.     struct RexxHostBase *RexxHostBase;
  125.  
  126.         /* Valid host port given? */
  127.  
  128.     if(RexxHost && RexxHost -> rh_SpecialID == 'REXX')
  129.     {
  130.             /* Remove it from the public list. */
  131.  
  132.         RemPort(&RexxHost -> rh_Port);
  133.  
  134.             /* Free the name. */
  135.  
  136.         FreeMem(RexxHost -> rh_Port . mp_Node . ln_Name,StrLen(RexxHost -> rh_Port . mp_Node . ln_Name) + 1);
  137.  
  138.             /* Free the allocated signal bit. */
  139.  
  140.         FreeSignal(RexxHost -> rh_Port . mp_SigBit);
  141.  
  142.             /* Free the body. */
  143.  
  144.         FreeMem(RexxHost,sizeof(struct RexxHost));
  145.     }
  146.  
  147.     return(NULL);
  148. }
  149.  
  150.     /* SendRexxCommand(HostPort,CommandString,FileExtension,HostName):
  151.      *
  152.      *    Sends a command to the rexx server, requires pointers
  153.      *    to the MsgPort of the calling Host and the command string.
  154.      *    File extension and host name are optional and may be
  155.      *    NULL.
  156.      */
  157.  
  158. LONG
  159. SendRexxCommand(struct RexxHost *HostPort,STRPTR CommandString,STRPTR FileExtension,STRPTR HostName)
  160. {
  161.     struct RexxHostBase *RexxHostBase;
  162.  
  163.     struct MsgPort    *RexxPort = (struct MsgPort *)FindPort(RXSDIR);
  164.     struct RexxMsg    *HostMessage;
  165.  
  166.         /* Valid pointers given? */
  167.  
  168.     if(CommandString && HostPort && HostPort -> rh_SpecialID == 'REXX' && RexxPort)
  169.     {
  170.             /* No special host name given? Take the MsgPort name. */
  171.  
  172.         if(!HostName)
  173.             HostName = (STRPTR)HostPort -> rh_Port . mp_Node . ln_Name;
  174.  
  175.             /* No file name extension? Take the default. */
  176.  
  177.         if(!FileExtension)
  178.             FileExtension = (STRPTR)"rexx";
  179.  
  180.             /* Create the message. */
  181.  
  182.         if(HostMessage = CreateRexxMsg((struct MsgPort *)HostPort,(char *)FileExtension,(char *)HostName))
  183.         {
  184.                 /* Add the command. */
  185.  
  186.             if(HostMessage -> rm_Args[0] = CreateArgstring((char *)CommandString,StrLen((char *)CommandString)))
  187.             {
  188.                     /* This is a command, not a function. */
  189.  
  190.                 HostMessage -> rm_Action = RXCOMM;
  191.  
  192.                     /* Release it... */
  193.  
  194.                 PutMsg(RexxPort,HostMessage);
  195.  
  196.                     /* Successful action. */
  197.  
  198.                 return(TRUE);
  199.             }
  200.  
  201.             DeleteRexxMsg(HostMessage);
  202.         }
  203.     }
  204.  
  205.     return(FALSE);
  206. }
  207.  
  208.     /* FreeRexxCommand(RexxMessage):
  209.      *
  210.      *    Frees the contents of a RexxMsg.
  211.      */
  212.  
  213. VOID
  214. FreeRexxCommand(struct RexxMsg *RexxMessage)
  215. {
  216.     struct RexxHostBase *RexxHostBase;
  217.  
  218.         /* Valid pointer given? */
  219.  
  220.     if(RexxMessage && RexxMessage -> rm_Node . mn_Node . ln_Type == NT_REPLYMSG)
  221.     {
  222.             /* Remove argument. */
  223.  
  224.         if(RexxMessage -> rm_Args[0])
  225.             DeleteArgstring((char *)RexxMessage -> rm_Args[0]);
  226.  
  227.             /* Free the message. */
  228.  
  229.         DeleteRexxMsg(RexxMessage);
  230.     }
  231. }
  232.  
  233.     /* ReplyRexxCommand(RexxMessage,Primary,Secondary,Result):
  234.      *
  235.      *    Sends a RexxMsg back to the rexx server, can include
  236.      *    result codes.
  237.      */
  238.  
  239. VOID
  240. ReplyRexxCommand(struct RexxMsg *RexxMessage,LONG Primary,LONG Secondary,STRPTR Result)
  241. {
  242.     struct RexxHostBase *RexxHostBase;
  243.  
  244.         /* Valid pointer given? */
  245.  
  246.     if(RexxMessage && RexxMessage -> rm_Node . mn_Node . ln_Type == NT_MESSAGE)
  247.     {
  248.             /* No secondary result and results wanted? */
  249.  
  250.         if(Secondary == NULL && (RexxMessage -> rm_Action & RXFF_RESULT))
  251.         {
  252.                 /* Build result string... */
  253.  
  254.             if(Result)
  255.                 Secondary = (LONG)CreateArgstring((char *)Result,StrLen((char *)Result));
  256.         }
  257.  
  258.             /* Set both results... */
  259.  
  260.         RexxMessage -> rm_Result1 = Primary;
  261.         RexxMessage -> rm_Result2 = Secondary;
  262.  
  263.             /* ...and reply the message. */
  264.  
  265.         ReplyMsg(RexxMessage);
  266.     }
  267. }
  268.  
  269.     /* GetRexxCommand(RexxMessage):
  270.      *
  271.      *    Returns a pointer to the command string if
  272.      *    the RexxMsg is a command request.
  273.      */
  274.  
  275. STRPTR
  276. GetRexxCommand(struct RexxMsg *RexxMessage)
  277. {
  278.     struct RexxHostBase *RexxHostBase;
  279.  
  280.     if(!RexxMessage || RexxMessage -> rm_Node . mn_Node . ln_Type == NT_REPLYMSG)
  281.         return(NULL);
  282.     else
  283.         return(RexxMessage -> rm_Args[0]);
  284. }
  285.  
  286.     /* GetRexxArg(RexxMessage):
  287.      *
  288.      *    Returns a pointer to the first RexxMsg argument.
  289.      */
  290.  
  291. STRPTR
  292. GetRexxArg(struct RexxMsg *RexxMessage)
  293. {
  294.     struct RexxHostBase *RexxHostBase;
  295.  
  296.     if(!RexxMessage)
  297.         return(NULL);
  298.     else
  299.         return(RexxMessage -> rm_Args[0]);
  300. }
  301.  
  302.     /* GetRexxResult1(RexxMessage):
  303.      *
  304.      *    Returns the 1st RexxMsg result.
  305.      */
  306.  
  307. LONG
  308. GetRexxResult1(struct RexxMsg *RexxMessage)
  309. {
  310.     struct RexxHostBase *RexxHostBase;
  311.  
  312.     if(!RexxMessage)
  313.         return(NULL);
  314.     else
  315.         return(RexxMessage -> rm_Result1);
  316. }
  317.  
  318.     /* GetRexxResult2(RexxMessage):
  319.      *
  320.      *    Returns the 2nd RexxMsg result.
  321.      */
  322.  
  323. LONG
  324. GetRexxResult2(struct RexxMsg *RexxMessage)
  325. {
  326.     struct RexxHostBase *RexxHostBase;
  327.  
  328.     if(!RexxMessage)
  329.         return(NULL);
  330.     else
  331.         return(RexxMessage -> rm_Result2);
  332. }
  333.  
  334.     /* IsSpace():
  335.      *
  336.      *    Returns TRUE if the input character is a space, tab,
  337.      *    carriage return, newline, form feed or vertical tab.
  338.      */
  339.  
  340. STATIC BYTE
  341. IsSpace(UBYTE c)
  342. {
  343.     if((c >= 13 && c <= 17) || c == 32)
  344.         return(TRUE);
  345.     else
  346.         return(FALSE);
  347. }
  348.  
  349.     /* GetToken(String,StartChar,AuxBuff,MaxLength):
  350.      *
  351.      *    Fills a string with the next given string
  352.      *    argument.
  353.      */
  354.  
  355. STRPTR
  356. GetToken(STRPTR String,LONG *StartChar,STRPTR AuxBuff,LONG MaxLength)
  357. {
  358.     struct RexxHostBase *RexxHostBase;
  359.  
  360.     SHORT i,StrEnd = 0,MaxPos = StrLen((char *)String);
  361.  
  362.         /* Last counter position. */
  363.  
  364.     if(MaxPos >= MaxLength + *StartChar)
  365.         MaxPos = MaxLength + *StartChar - 1;
  366.  
  367.         /* Already finished with argument string? */
  368.  
  369.     if(*StartChar <= StrLen((char *)String) - 1 && String && String[0] && AuxBuff && MaxLength)
  370.     {
  371.             /* Parse the argument string... */
  372.  
  373.         for(i = *StartChar ; i <= MaxPos ; i++)
  374.         {
  375.                 /* Skip leading blanks... */
  376.  
  377.             if(!StrEnd && IsSpace(String[i]))
  378.             {
  379.                 while(IsSpace(String[i]) && i < MaxPos)
  380.                 {
  381.                     i++;
  382.  
  383.                     (*StartChar)++;
  384.                 }
  385.             }
  386.  
  387.                 /* Found an argument. */
  388.  
  389.             if(IsSpace(String[i]) || String[i] == 0)
  390.             {
  391.                     /* Copy it to the auxiliary buffer. */
  392.  
  393.                 StrNCpy((char *)AuxBuff,(char *)(String + *StartChar),StrEnd);
  394.                 AuxBuff[StrEnd] = 0;
  395.  
  396.                     /* Change the position counter (since
  397.                      * we can't use static data initialisation
  398.                      * calling program has to supply a
  399.                      * counter variable).
  400.                      */
  401.  
  402.                 (*StartChar) += StrEnd;
  403.  
  404.                 return(AuxBuff);
  405.             }
  406.  
  407.                 /* Increment character counter. */
  408.  
  409.             StrEnd++;
  410.         }
  411.     }
  412.  
  413.     return(NULL);
  414. }
  415.  
  416.     /* GetStringValue(String):
  417.      *
  418.      *    Returns the numeric value taken from given string
  419.      *    (just like atoi(), taken from example source code
  420.      *    by K&R).
  421.      */
  422.  
  423. LONG
  424. GetStringValue(STRPTR String)
  425. {
  426.     struct RexxHostBase *RexxHostBase;
  427.  
  428.     LONG    Value;
  429.     BYTE    Sign = 1;
  430.     SHORT    i;
  431.  
  432.         /* Valid argument given? */
  433.  
  434.     if(String && !String[0])
  435.     {
  436.             /* Skip leading blank characters. */
  437.  
  438.         for(i = 0 ; String[i] == ' ' || String[i] == '\n' || String[i] == '\t' ; i++);
  439.  
  440.             /* Remember sign extension. */
  441.  
  442.         if(String[i] == '+' || String[i] == '-')
  443.             Sign = (String[i++] == '+') ? 1 : -1;
  444.  
  445.             /* Convert from ASCII to decimal. */
  446.  
  447.         for(Value = 0 ; String[i] >= '0' && String[i] <= '9' ; i++)
  448.             Value = 10 * Value + String[i] - '0';
  449.  
  450.             /* Return real value. */
  451.  
  452.         return(Sign * Value);
  453.     }
  454.  
  455.     return(0);
  456. }
  457.  
  458.     /* BuildValueString(Value,String):
  459.      *
  460.      *    Puts a numeric value in decimal form into a
  461.      *    given string (similar to itoa(), taken from
  462.      *    example source code by K&R).
  463.      */
  464.  
  465. STRPTR
  466. BuildValueString(LONG Value,STRPTR String)
  467. {
  468.     struct RexxHostBase *RexxHostBase;
  469.  
  470.     SHORT    i = 0,j;
  471.     LONG    Sign;
  472.     UBYTE    c;
  473.  
  474.         /* Valid argument given? */
  475.  
  476.     if(String)
  477.     {
  478.             /* Remember sign extension. */
  479.  
  480.         if((Sign = Value) < 0)
  481.             Value = -Value;
  482.  
  483.             /* Convert it into ASCII characters (in
  484.              * reverse order, i.e. 1234 = "4321").
  485.              */
  486.  
  487.         do
  488.             String[i++] = Value % 10 + '0';
  489.         while((Value /= 10) > 0);
  490.  
  491.             /* Add sign extension. */
  492.  
  493.         if(Sign < 0)
  494.             String[i++] = '-';
  495.  
  496.             /* String NULL-termination. */
  497.  
  498.         String[i] = 0;
  499.  
  500.             /* Reverse the string. */
  501.  
  502.         for(i = 0, j = StrLen((char *)String) - 1 ; i < j ; i++, j--)
  503.         {
  504.             c        = String[i];
  505.             String[i]    = String[j];
  506.             String[j]    = c;
  507.         }
  508.     }
  509.  
  510.     return(String);
  511. }
  512.  
  513.     /* AmigaToUpper(c):
  514.      *
  515.      *    Replacement for toupper() macro, also knows how to
  516.      *    map international characters to uppercase. Note: not
  517.      *    a real library module.
  518.      */
  519.  
  520. STATIC UBYTE
  521. AmigaToUpper(UBYTE c)
  522. {
  523.     /* -------- DEC ---------    -------- ASCII ------- */
  524.  
  525.     if((c >= 224 && c <= 254) || (c >= 'a' && c <= 'z'))
  526.         c -= 32;
  527.  
  528.     return(c);
  529. }
  530.  
  531.     /* RexxStrCmp(Source,Target):
  532.      *
  533.      *    Compares two strings ignoring case.
  534.      */
  535.  
  536. LONG
  537. RexxStrCmp(STRPTR Source,STRPTR Target)
  538. {
  539.     struct RexxHostBase *RexxHostBase;
  540.  
  541.         /* Do the string comparison ignoring case. */
  542.  
  543.     for( ; AmigaToUpper(*Source) == AmigaToUpper(*Target) ; Source++, Target++)
  544.     {
  545.         if(!(*Source))
  546.             return(0);
  547.     }
  548.  
  549.     return(AmigaToUpper(*Source) - AmigaToUpper(*Target));
  550. }
  551.  
  552.     /* GetRexxMsg():
  553.      *
  554.      *    Picks up pending RexxMessages from a RexxHost and
  555.      *    returns them to the caller. I desired, will wait
  556.      *    for new messages to arrive if none is present yet.
  557.      */
  558.  
  559. struct RexxMsg *
  560. GetRexxMsg(struct RexxHost *RexxHost,LONG Wait)
  561. {
  562.     struct RexxHostBase    *RexxHostBase;
  563.     struct RexxMsg        *RexxMessage = NULL;
  564.  
  565.         /* Valid pointer given? */
  566.  
  567.     if(RexxHost && RexxHost -> rh_SpecialID == 'REXX')
  568.     {
  569.             /* Try to pick up a message. */
  570.  
  571.         while(!(RexxMessage = (struct RexxMsg *)GetMsg((struct MsgPort *)RexxHost)))
  572.         {
  573.                 /* No message available. Are we to wait? */
  574.  
  575.             if(Wait)
  576.                 WaitPort((struct MsgPort *)RexxHost);
  577.             else
  578.                 break;
  579.         }
  580.     }
  581.  
  582.         /* Return the result (may be NULL). */
  583.  
  584.     return(RexxMessage);
  585. }
  586.  
  587.     /* SendRexxMsg():
  588.      *
  589.      *    Sends a single (or a list of) command(s) to Rexx host
  590.      *    and returns the secondary result.
  591.      */
  592.  
  593. ULONG
  594. SendRexxMsg(STRPTR HostName,STRPTR *MsgList,STRPTR SingleMsg,LONG GetResult)
  595. {
  596.     struct RexxHostBase    *RexxHostBase;
  597.     struct RexxMsg        *RexxMessage;
  598.     struct MsgPort        *HostPort,*ReplyPort;
  599.     ULONG             Result = 0;
  600.     SHORT             i;
  601.  
  602.         /* Valid pointers given? */
  603.  
  604.     if(HostName && (MsgList || SingleMsg))
  605.     {
  606.             /* Can we find the host? */
  607.  
  608.         if(HostPort = (struct MsgPort *)FindPort((char *)HostName))
  609.         {
  610.                 /* Allocate a reply port. */
  611.  
  612.             if(ReplyPort = (struct MsgPort *)AllocMem(sizeof(struct MsgPort),MEMF_PUBLIC | MEMF_CLEAR))
  613.             {
  614.                 if((ReplyPort -> mp_SigBit = AllocSignal(-1)) != -1)
  615.                 {
  616.                     ReplyPort -> mp_Node . ln_Type    = NT_MSGPORT;
  617.                     ReplyPort -> mp_Flags        = PA_SIGNAL;
  618.                     ReplyPort -> mp_SigTask        = SysBase -> ThisTask;
  619.  
  620.                     InitList(&ReplyPort -> mp_MsgList);
  621.  
  622.                         /* Create a Rexx message. */
  623.  
  624.                     if(RexxMessage = (struct RexxMsg *)CreateRexxMsg(ReplyPort,"",(char *)HostName))
  625.                     {
  626.                             /* A list of arguments or only a single arg? */
  627.  
  628.                         if(MsgList)
  629.                         {
  630.                             for(i = 0 ; i < 16 ; i++)
  631.                                 RexxMessage -> rm_Args[i] = MsgList[i];
  632.                         }
  633.                         else
  634.                             RexxMessage -> rm_Args[0] = SingleMsg;
  635.  
  636.                             /* Do we want result codes? */
  637.  
  638.                         if(GetResult)
  639.                             RexxMessage -> rm_Action = RXFF_RESULT;
  640.  
  641.                             /* Send packet and wait for the reply. */
  642.  
  643.                         PutMsg(HostPort,RexxMessage);
  644.                         WaitPort(ReplyPort);
  645.  
  646.                             /* Remember result. */
  647.  
  648.                         if(GetResult && !RexxMessage -> rm_Result1)
  649.                             Result = RexxMessage -> rm_Result2;
  650.  
  651.                             /* Remove Rexx message. */
  652.  
  653.                         DeleteRexxMsg(RexxMessage);
  654.                     }
  655.  
  656.                         /* Free reply port signal bit. */
  657.  
  658.                     FreeSignal(ReplyPort -> mp_SigBit);
  659.                 }
  660.  
  661.                     /* Free the replyport itself. */
  662.  
  663.                 FreeMem(ReplyPort,sizeof(struct MsgPort));
  664.             }
  665.         }
  666.     }
  667.  
  668.         /* Return the result. */
  669.  
  670.     return(Result);
  671. }
  672.  
  673.     /* GetRexxString():
  674.      *
  675.      *    Copy the result string returned by SendRexxMsg to user
  676.      *    buffer and/or remove the original string.
  677.      */
  678.  
  679. VOID
  680. GetRexxString(STRPTR SourceString,STRPTR DestString)
  681. {
  682.     struct RexxHostBase *RexxHostBase;
  683.  
  684.         /* Valid pointer given? */
  685.  
  686.     if(SourceString)
  687.     {
  688.             /* Destination memory buffer given? */
  689.  
  690.         if(DestString)
  691.             StrCpy((char *)DestString,(char *)SourceString);
  692.  
  693.             /* Deallocate the original string. */
  694.  
  695.         DeleteArgstring((char *)SourceString);
  696.     }
  697. }
  698.  
  699.     /* GetRexxClip():
  700.      *
  701.      *    Searches the rexx clip list for a node with given
  702.      *    name.
  703.      */
  704.  
  705. LONG
  706. GetRexxClip(char *Name,LONG WhichArg)
  707. {
  708.     struct RexxHostBase *RexxHostBase;
  709.  
  710.         /* Do we have valid buffers and size? */
  711.  
  712.     if(Name && Name[0])
  713.     {
  714.         struct RexxRsrc *Node;
  715.  
  716.             /* Can we find the clip node? */
  717.  
  718.         if(Node = (struct RexxRsrc *)FindRsrcNode(&RexxSysBase -> rl_ClipList,Name,RRT_CLIP))
  719.         {
  720.             if(WhichArg)
  721.                 return(Node -> rr_Arg1);
  722.             else
  723.                 return(Node -> rr_Arg2);
  724.         }
  725.     }
  726.  
  727.     return(NULL);
  728. }
  729.